#include "StdAfx.h"
#include "AnimationManager.h"
#include "Utility\ColladaFile.h"
#include "Utility\ColladaGeometry.h"
#include "Animation.h"
#include "AnimationInstance.h"

AnimationManager* AnimationManager::m_spAnimationMgr = 0;

AnimationManager::AnimationManager()
{
	m_pAnimations = new Map<u32, Animation*>();
}

AnimationManager::~AnimationManager(void)
{
	delete m_pAnimations;
}

AnimationManager* AnimationManager::GetInstance()
{
	if( !m_spAnimationMgr )
		m_spAnimationMgr = new AnimationManager();

	return m_spAnimationMgr;
}

void AnimationManager::CreateAnimationFromFile(u32 uName, ColladaFile* pFile)
{
	FixedArray<ColladaFile::sBone>* bones = pFile->GetBones();
	Map<u32, ColladaFile::sBoneData>* pBoneIndiceMap = pFile->GetBoneIndiceMap();
	FixedArray<Matrix>*	paInvBindMatricies = pFile->GetInverseBinds();
	Animation* pAnimatin = new Animation(bones->GetNumElements());

	//Make sure their are bones being animated, if so then create a new animation and add them to it
	if( paInvBindMatricies->GetNumElementsUsed() > 0 )
	{

		Animation* pAnimation = new Animation(paInvBindMatricies->GetNumElementsUsed());
		for(int i = 0; i < paInvBindMatricies->GetNumElementsUsed(); i++ )
		{
			ColladaFile::sBone bone = (*bones)[i];
			
			ColladaFile::sBoneData* sData = (*pBoneIndiceMap)[bone.uName];
			ColladaFile::sBoneData* sParent = (*pBoneIndiceMap)[sData->uParent];
							
			Matrix mParent, mBindPose, mInvBind;
			mParent.Identity();				
			mInvBind = (*paInvBindMatricies)[i];				

			if( sParent )
			{					
				mParent = sParent->mWorld;								
				bone.iParent = sParent->iIndex;	
			}		
			else				
				bone.iParent = -1;	

			mBindPose = mInvBind * ( sData->mWorld * mParent );	

			for(int j = 0; j < bone.aTransforms.GetNumElementsUsed(); j++)
			{					
				Matrix mTransform = bone.aTransforms[j];
				Matrix mFinal = mInvBind * ( mTransform * mParent );					
				bone.aTransforms[j] = mFinal;
			}				
				

			//If not transforms add the visual scene transform
			if( bone.aTransforms.GetNumElements() == 0 )
			{
				bone.aTransforms.SetSize(1);				
				bone.aTransforms.Add(mBindPose);					
			}

			//remove difference between ref pose and current pose
			mBindPose.Invert();
			sData->mWorld = (sData->mWorld * mParent) * mBindPose;

			pAnimation->AddBone(sData->iIndex, new Animation::sBone(&bone) );
			
		}	
		m_pAnimations->Add(uName, pAnimation);
	}
}

AnimationInstance*	AnimationManager::GetNewAnimation(u32 uName)
{
	Animation** pAnimation = (*m_pAnimations)[uName];

	if( pAnimation )	
		return new AnimationInstance(*pAnimation);

	return 0;
}